<template>
  <div class="chips-selected"
       ref="chips__selected"
       @focus.capture="chipsFocusHandler">
    <!-- 输入框 -->
    <div class="p-inputgroup" @click="chipsFocusHandler">
      <span ref="chips__selected__addon"
            class="p-inputgroup-addon"
            :class="props.customerAddonClass"
            :style="props.customerAddonStyle"
            v-if="addon&&addon !== ''">
        {{ addon }}
      </span>
      <Chips ref="chips__input"
             v-model="chipsSelections"
             separator=","
             :max="props.max"
             @add="chipsAddHandler"
             @focus.capture="selectShow = true;"/>
    </div>
    <!-- 下拉选项 -->
    <span class="absolute">
      <Card v-mounted
            class="relative z-5 chips__selected__card"
            ref="chips__selected__card">
        <template #content>
          <div class="field-checkbox"
               v-for="(item, index) of selections"
               :key="index">
            <Checkbox name="selected"
                      v-model="chipsSelections"
                      :value="item"
                      @click="checkBoxLabelClickHandler"/>
            <label @click="checkBoxLabelClickHandler">{{ item }}</label>
          </div>
          <div v-if="selections.length === 0" class="text-center">
              {{ props.emptyText }}
          </div>
        </template>
      </Card>
    </span>

  </div>
</template>
<script setup lang="ts">
/** JS */
import {ref, defineProps, onMounted, watch, Ref, withDefaults, nextTick, defineEmits} from 'vue';
/** 组件 */
import Chips from 'primevue/chips';
import Card from 'primevue/card';
import Checkbox from 'primevue/checkbox';

/** props 参数 */
interface ChipsSelectedProps {
  // 选项
  items: string [],
  // 默认选项
  defaultSelected?: string[],
  // 是否允许新增, 默认为允许
  openAdd?: boolean,
  // 标签
  addon?: string,
  // 是否过滤
  filter?: boolean,
  // 最大数量
  max?: number,
  // 分隔符
  separator?: string,
  // 开启输入模式
  input?: boolean,
  // 输入框输入提示
  placeholder?: string,
  // 空数据时的文字
  emptyText?: string,
  // 选项卡的高度
  cardHeight?: number,
  // 自定义 addon 的 class\style
  customerAddonClass?: string,
  customerAddonStyle?: string
}

/** 参数钩子 */
const props = withDefaults(defineProps<{
      // 选项
      items: string [],
      // 默认选项
      defaultSelected?: string[],
      // 是否允许新增, 默认为允许
      openAdd?: boolean,
      // 标签
      addon?: string,
      // 是否过滤
      filter?: boolean,
      // 最大数量
      max?: number,
      // 分隔符
      separator?: string,
      // 开启输入模式
      input?: boolean,
      // 输入框输入提示
      placeholder?: string,
      // 空数据时的文字
      emptyText?: string,
      // 选项卡的高度
      cardHeight?: number,
      // 自定义 addon 的 class\style
      customerAddonClass?: string,
      customerAddonStyle?: string
    }>(), {
      max: 5,
      openAdd: true,
      separator: ',',
      input: true,
      emptyText: '没有数据',
      cardHeight: 150,
    }),
    buildDefaultPlaceHolder = () => {
      if (!props.placeholder) return `输入内容并以“${props.separator}”为分隔符`;
      else return props.placeholder;
    };
const emits = defineEmits(['change'])
/** 选项 */
const selections: Ref<string []> = ref(props.items),
    tempSelections: Ref<string []> = ref(props.items),
    chipsSelections: Ref<any []> = ref([]);
const chipsIsMax = () => {
  return chipsSelections.value.length > props.max;
}
watch(() => props.items, (newItems) => {
  // 添加默认值
  selections.value = newItems;
  if (tempSelections.value.length === 0) {
    tempSelections.value = newItems;
  }
  // 有数据时记录数据后的高度
  nextTick(() => {
    if (chips__selected__card.value) {
      let element: HTMLElement = chips__selected__card.value.$el as HTMLElement;
      let scrollHeight = element.scrollHeight, clientHeight = element.clientHeight;
      // 记录默认高度
      if (scrollHeight >= clientHeight) {
        cardHeight.value = scrollHeight;
      } else {
        cardHeight.value = clientHeight;
      }
      // 清除高度
      element.style.height = '0px';
    }
  });
})
const selectionCheckboxClickHandler = () => {
  // 防止选择溢出
  nextTick(() => {
    if (chipsIsMax()) {
      chipsSelections.value.pop();
    }
  })
};
/** 监听 addon */
const addon = ref(props.addon)
watch(() => props.addon, (newAddon) => {
  addon.value = newAddon;
});
/** 选项框 */
const selectShow = ref(false), tempSelect = ref(null);
// 选项卡片的宽度
const cardWidth = ref(0), cardHeight = ref(0);
const chipsFocusHandler = () => {
      selectShow.value = true;
      (chips__input.value as any).focused = true;
      tempSelect.value = chips__input.value
      // 恢复高度
      if (chips__selected__card.value) {
        let element: HTMLElement = chips__selected__card.value.$el as HTMLElement
        element.style.height = cardHeight.value + 'px';
      }
    },
    checkBoxLabelClickHandler = (event: PointerEvent) => {
      if (event.target) {
        let element = event.target as HTMLElement;
        let txt = element.innerHTML;
        if (chipsSelections.value.length === 0) {
          chipsSelections.value.push(element.innerHTML);
        } else {
          // label 加入时去重
          let index = 0;
          for (let chipsVal of chipsSelections.value) {
            if (chipsVal.toLocaleLowerCase().trim() !== txt.toLocaleLowerCase().trim()) {
              // 任意大小类似或相同排除
              chipsSelections.value.push(element.innerHTML);
              // 防溢出
              selectionCheckboxClickHandler();
            } else {
              chipsSelections.value.splice(index, 1);
            }
          }
          index++;
        }
      }
    }
/** 组件元素 ref */
const chips__selected__addon = ref(null), chips__selected__card: Ref<any> = ref(null), chips__input = ref(null);
const tempChips = ref(null)
// 自定义挂载指令
const vMounted = {
  handler: (event: any) => {
    let pe: any = event, card: any, input: any;
    const path = pe.path || (pe.composedPath && pe.composedPath());
    // 监听是否在 card 范围内，如果不在那么隐藏选择框
    if (path && path.length > 0 && (card = chips__selected__card.value) && (input = chips__input.value)) {
      if ((path as any[]).indexOf(card.$el) === -1 && path.indexOf(input.$el) === -1) {
        // selectShow.value = false;
        card.$el.style.height = '0px';
        input.focused = false;
      }
    }
  },
  mounted(el: HTMLElement) {
    // 初始化卡片宽度
    if (chips__input.value) {
      let width = (chips__input.value as any).$el.offsetWidth;
      if (props?.addon && props.addon !== '') {
        cardWidth.value = width - 7;
        let offsetWidth = (chips__selected__addon.value as any)?.offsetWidth;
        el.style.left = offsetWidth + 1 + 'px';
      } else {
        cardWidth.value = width;
      }
    }
    el.style.width = cardWidth.value + 'px';
    el.style.borderRadius = '0px 0px 6px 6px';
    // 监听当前组件的全局点击事件
    document.addEventListener('click', vMounted.handler);
    // FIXME：此处会导致全组件的全局监听
    // 监听全局点击事件
    // document.onclick = (event) => {
    //   // 监听是否在 card 范围内，如果不在那么隐藏选择框
    //   let pe: any = event, card: any, input: any;
    //   if (pe.path && pe.path.length > 0 && (card = chips__selected__card.value) && (input = chips__input.value)) {
    //     if ((pe.path as any[]).indexOf(card.$el) === -1 && pe.path.indexOf(input.$el) === -1) {
    //       selectShow.value = false;
    //     }
    //   }
    // }
  },
  unmounted() {
    document.removeEventListener('click', vMounted.handler);
  }
}
/** 监听 chips */
const inputDom: Ref<HTMLInputElement | null | undefined> = ref(null), openInput = ref(true);
const chipsAddHandler = (event) => {
  if (props.openAdd) {
    if (chipsSelections.value[0]) {
      chipsSelections.value = Array.from(new Set(chipsSelections.value))
    }
    let {value} = event;
    if (value) {
      for (let val of value) {
        let trimVal = val.trim();
        if (tempSelections.value.indexOf(trimVal) === -1) {
          tempSelections.value.push(trimVal);
        }
        selections.value = tempSelections.value;
      }
    }
  } else {
    let {value} = event;
    if (value) {
      for (let valueElement of value) {
        if (tempSelections.value.indexOf(valueElement) === -1) chipsSelections.value.pop();
      }
    }
  }
};
// FIXME：first --> 此处遍历组件会发生多次遍历，点击 checkbox 可能会卡死。--> chipsSelections 等于自己的 newValue 导致多次数据监听
watch(() => chipsSelections.value, (n, o) => {
  if (n.length === 0) {
    selections.value = tempSelections.value;
  }
  // chipsSelections.value = Array.from(new Set(n));
  let inputEle = inputDom.value;
  if (inputEle) {
    if (chipsSelections.value.length >= props.max) {
      inputEle.placeholder = '';
      nextTick(() => {
        openInput.value = false;
        inputEle.value = '';
      });
      // 重新聚焦并打开监听 backspace 事件
      let clearDisabled = setInterval(() => {
        inputEle.removeAttribute('disabled');
        if (!inputEle.hasAttribute('disabled')) {
          inputEle.focus();
          window.clearInterval(clearDisabled);
        }
      }, 50);
    } else {
      openInput.value = true;
      if (props.input) {
        inputEle.placeholder = buildDefaultPlaceHolder();
      }
    }
    if (JSON.stringify(n) !== JSON.stringify(o)) {
      emits('change', chipsSelections.value);
    }
  }
});
// 默认选项
watch(() => props.defaultSelected, (n) => {
  if (n) {
    // 没有默认选项或者由外部进行了清空操作。
    if (n.length === 0) {
      chipsSelections.value.splice(0);
      if (inputDom.value) {
        inputDom.value.placeholder = buildDefaultPlaceHolder();
      }
    } else if (n.filter(i => selections.value.includes(i))) {
      // 有默认选项，但是必须 items 也包含
      chipsSelections.value.push(...n);
      nextTick(() => {
        if (chipsSelections.value.length >= props.max) {
          if (inputDom.value) {
            inputDom.value.placeholder = '';
          }
        }
      })
    } else {
      console.error('请确保默认值在 items 中也存在');
    }
  }
})
/** 初始化挂载 */
onMounted(() => {
  nextTick(() => {
    if (chips__selected__card.value) {
      let element: HTMLElement = chips__selected__card.value.$el as HTMLElement;
      let scrollHeight = element.scrollHeight, clientHeight = element.clientHeight;
      // 记录默认高度
      if (scrollHeight >= clientHeight) {
        cardHeight.value = scrollHeight;
      } else {
        cardHeight.value = clientHeight;
      }
      // 清除高度
      element.style.height = '0px';
    }
  })


  // 根据钩子函数进行初始化
  inputDom.value = (chips__input.value as any)?.$refs.input;
  let inputEl = inputDom.value;
  // 动态可选框
  if (inputEl) {
    if (!props.input && inputDom) {
      inputEl.disabled = true;
    } else {
      // 允许输入
      let placeholder = buildDefaultPlaceHolder();
      if (props.placeholder && props.placeholder.trim() !== '') {
        placeholder = props.placeholder;
      }
      inputEl.placeholder = placeholder;
      if (props.filter) {
        // 过滤操作
        inputEl.oninput = () => {
          if (inputEl) {
            if (!openInput.value) {
              inputEl.value = '';
              return;
            }
            let val = inputEl.value, isMax = chipsIsMax();
            if (val.trim() !== '' && !isMax) {
              let newSelections = tempSelections.value.filter(selected => {
                return selected.indexOf(val) !== -1;
              });
              selections.value = newSelections;
            } else {
              selections.value = tempSelections.value;
            }
          }
        }
      }
    }
  }
});
</script>

<style lang="less" scoped>

@-webkit-keyframes fadeInDown {
  from {
    opacity: 0;
    -webkit-transform: translate3d(0, -15%, 0);
    transform: translate3d(0, -10%, 0);
  }

  to {
    opacity: 1;
    -webkit-transform: translate3d(0, 0, 0);
    transform: translate3d(0, 0, 0);
  }
}

@keyframes fadeInDown {
  from {
    opacity: 0;
    -webkit-transform: translate3d(0, -15%, 0);
    transform: translate3d(0, -10%, 0);
  }

  to {
    opacity: 1;
    -webkit-transform: translate3d(0, 0, 0);
    transform: translate3d(0, 0, 0);
  }
}

.animate__fadeInDown {
  -webkit-animation-name: fadeInDown;
  animation-name: fadeInDown;
}


@-webkit-keyframes fadeOutUp {
  from {
    opacity: 1;
  }

  to {
    opacity: 0;
    -webkit-transform: translate3d(0, -25%, 0);
    transform: translate3d(0, -25%, 0);
  }
}

@keyframes fadeOutUp {
  from {
    opacity: 1;
  }

  to {
    opacity: 0;
    -webkit-transform: translate3d(0, -25%, 0);
    transform: translate3d(0, -25%, 0);
  }
}

.animate__fadeOutUp {
  -webkit-animation-name: fadeOutUp;
  animation-name: fadeOutUp;
}
</style>